#include "my_hooks.h"
#include "my_handlers.h"

my_hook_chain_t *global_hook_chain = NULL;
my_hook_chain_t *worker_init_chain = NULL;
my_hook_chain_t *worker_quit_chain = NULL;
my_hook_chain_t *tcp_accept_init_chian = NULL;
my_hook_chain_t *tcp_accept_quit_chian = NULL;

static inline void
my_hook_init(my_hook_chain_t *chain)
{
    my_queue_init(&chain->head);
}

static void
my_hook_chain_free(void *data)
{
    my_hook_item_t *item;
    my_hook_chain_t *chain = (my_hook_chain_t *)data;
    my_queue_t *q = my_queue_head(&chain->head);
    while (q != &chain->head) {
        item = my_queue_data(q, my_hook_item_t, queue);
        q = q->next;
        my_thread_free(item);
    }

    my_thread_free(chain);
}

void
my_hooks_init()
{
    my_hook_chain_t *chain;

    chain = my_thread_calloc(sizeof(my_hook_chain_t));
    my_hook_init(chain);
    my_cleanup_handler_add(&g_cleanup_list,
        my_hook_chain_free, chain);
    global_hook_chain = chain;

    chain = my_thread_calloc(sizeof(my_hook_chain_t));
    my_hook_init(chain);
    my_cleanup_handler_add(&g_cleanup_list,
        my_hook_chain_free, chain);
    worker_init_chain = chain;

    chain = my_thread_calloc(sizeof(my_hook_chain_t));
    my_hook_init(chain);
    my_cleanup_handler_add(&g_cleanup_list,
        my_hook_chain_free, chain);
    worker_quit_chain = chain;

    chain = my_thread_calloc(sizeof(my_hook_chain_t));
    my_hook_init(chain);
    my_cleanup_handler_add(&g_cleanup_list,
        my_hook_chain_free, chain);
    tcp_accept_init_chian = chain;

    chain = my_thread_calloc(sizeof(my_hook_chain_t));
    my_hook_init(chain);
    my_cleanup_handler_add(&g_cleanup_list,
        my_hook_chain_free, chain);
    tcp_accept_quit_chian = chain;
}

void
my_hook_chain_register(my_hook_chain_t *chain,
    my_hook_handler_pt hook_handler)
{
    my_hook_item_t *hook_item =
        my_thread_calloc(sizeof(my_hook_item_t));
    hook_item->handler = hook_handler;
    my_queue_insert_tail(&chain->head, &hook_item->queue);
}

void
my_hook_chain_exec(my_hook_chain_t *chain, void *data)
{
    my_hook_item_t *item;
    my_queue_t *q = my_queue_head(&chain->head);
    while (q != &chain->head) {
        item = my_queue_data(q, my_hook_item_t, queue);
        item->handler(data);
        q = q->next;
    }
}